package mathsys2;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 习题类：《面向对象软件构造》4.1-4.5节需求+《模块化软件构造》故事一至三
 * 核心功能：生成指定数量习题、格式化显示、去重校验
 */
public class ExerciseSet {
    private final List<Arithmetic> exercises = new ArrayList<>();
    private final int totalCount; // 计划生成数量（固定50道，匹配实验需求）
    private final int minNum = 0; // 运算数最小值（0，100以内约束）
    private final int maxNum = 100; // 运算数最大值（100，100以内约束）
    private final boolean isMixed; // 是否混合类型
    private final Random random = new Random();

    // 构造方法：指定数量与类型（实验固定50道）
    public ExerciseSet(int totalCount, boolean isMixed) {
        if (totalCount != 50) {
            throw new IllegalArgumentException("实验要求生成50道习题（当前输入：" + totalCount + "道）");
        }
        this.totalCount = totalCount;
        this.isMixed = isMixed;
    }

    // -------------------------- 生成50道加法习题（《面向对象软件构造》4.5节） --------------------------
    public void generateAdditions() {
        clearExercises();
        int maxAttempts = totalCount * 20; // 避免死循环
        int attempt = 0;

        while (exercises.size() < totalCount && attempt < maxAttempts) {
            // 生成符合约束的加法运算数（和≤100）
            int num1 = random.nextInt(maxNum - minNum + 1) + minNum;
            int num2 = random.nextInt((maxNum - num1) - minNum + 1) + minNum;
            Arithmetic add = new Arithmetic(num1, num2, '+');

            if (!exercises.contains(add)) { // 去重（依赖Arithmetic.equals()）
                exercises.add(add);
            }
            attempt++;
        }

        if (exercises.size() != totalCount) {
            throw new IllegalStateException("加法习题生成失败：仅生成" + exercises.size() + "道（目标50道）");
        }
    }

    // -------------------------- 生成50道减法习题（《面向对象软件构造》4.4节） --------------------------
    public void generateSubtractions() {
        clearExercises();
        int maxAttempts = totalCount * 20;
        int attempt = 0;

        while (exercises.size() < totalCount && attempt < maxAttempts) {
            // 生成符合约束的减法运算数（差≥0）
            int num2 = random.nextInt(maxNum - minNum + 1) + minNum;
            int num1 = random.nextInt(maxNum - num2 + 1) + num2;
            Arithmetic sub = new Arithmetic(num1, num2, '-');

            if (!exercises.contains(sub)) { // 去重
                exercises.add(sub);
            }
            attempt++;
        }

        if (exercises.size() != totalCount) {
            throw new IllegalStateException("减法习题生成失败：仅生成" + exercises.size() + "道（目标50道）");
        }
    }

    // -------------------------- 生成50道混合习题（《面向对象软件构造》4.2节） --------------------------
    public void generateMixedExercises() {
        if (!isMixed) {
            throw new IllegalStateException("当前为单一类型习题集，无法生成混合习题");
        }
        clearExercises();
        int addTarget = 25; // 混合习题：加法25道+减法25道（1:1比例，《模块化软件构造》故事三）
        int subTarget = 25;
        int maxAttempts = totalCount * 20;
        int attempt = 0;

        // 先生成25道加法
        while (exercises.stream().filter(a -> a.getOperator() == '+').count() < addTarget && attempt < maxAttempts) {
            int num1 = random.nextInt(maxNum - minNum + 1) + minNum;
            int num2 = random.nextInt((maxNum - num1) - minNum + 1) + minNum;
            Arithmetic add = new Arithmetic(num1, num2, '+');
            if (!exercises.contains(add)) {
                exercises.add(add);
            }
            attempt++;
        }

        // 再生成25道减法
        while (exercises.stream().filter(a -> a.getOperator() == '-').count() < subTarget && attempt < maxAttempts) {
            int num2 = random.nextInt(maxNum - minNum + 1) + minNum;
            int num1 = random.nextInt(maxNum - num2 + 1) + num2;
            Arithmetic sub = new Arithmetic(num1, num2, '-');
            if (!exercises.contains(sub)) {
                exercises.add(sub);
            }
            attempt++;
        }

        if (exercises.size() != totalCount) {
            throw new IllegalStateException("混合习题生成失败：仅生成" + exercises.size() + "道（目标50道）");
        }
    }

    // -------------------------- 格式化显示（《面向对象软件构造》4.3节+《模块化软件构造》故事二） --------------------------
    public void printExercises(int perLine) {
        if (perLine < 1) {
            throw new IllegalArgumentException("每行显示数量必须≥1（实验建议每行5道）");
        }
        if (exercises.isEmpty()) {
            System.out.println("习题集为空，请先生成习题");
            return;
        }

        // 标题（标注类型与数量）
        String type = isMixed ? "混合（加法25道+减法25道）" :
                (exercises.get(0).getOperator() == '+' ? "加法" : "减法");
        System.out.println("=== 100以内" + type + "习题（共50道，每行" + perLine + "道） ===");

        // 左对齐显示，确保整齐
        for (int i = 0; i < exercises.size(); i++) {
            System.out.printf("%-12s", exercises.get(i).toString());
            if ((i + 1) % perLine == 0) {
                System.out.println();
            }
        }
        if (exercises.size() % perLine != 0) {
            System.out.println();
        }
    }

    // -------------------------- 辅助方法（校验与管理） --------------------------
    // 校验习题是否重复（《模块化软件构造》故事三）
    public boolean hasDuplicate() {
        for (int i = 0; i < exercises.size(); i++) {
            for (int j = i + 1; j < exercises.size(); j++) {
                if (exercises.get(i).equals(exercises.get(j))) {
                    return true;
                }
            }
        }
        return false;
    }

    // 校验结果是否符合约束（《模块化软件构造》故事二）
    public boolean isResultValid() {
        for (Arithmetic a : exercises) {
            if (a.getOperator() == '+' && a.getResult() > 100) return false;
            if (a.getOperator() == '-' && a.getResult() < 0) return false;
        }
        return true;
    }

    public void clearExercises() { exercises.clear(); }
    public List<Arithmetic> getExercises() { return new ArrayList<>(exercises); }
    public int getGeneratedCount() { return exercises.size(); }
}